package com.lznAdmin.base.common.aspect;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.lznAdmin.base.common.api.service.CommonAPI;
import com.lznAdmin.base.common.aspect.annotation.Dict;
import com.lznAdmin.base.common.vo.DictVO;
import com.lznAdmin.base.lznAdminResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Description: 字典aop类
 * @Author: lzn
 * @Date: 2022-02-17 16:28
 **/
@Aspect
@Component
@Slf4j
public class DictAspect {
    @Autowired
    private CommonAPI commonAPI;

    @Value("${spring.jackson.date-format}")
    private String dateFormat;

    /**
     * listMap去重
     *
     * @param listMap
     * @return listMap
     */
    private static Map<String, List<String>> listMapRemoveDuplicate(Map<String, List<String>> listMap) {
        for (String key : listMap.keySet()) {
            HashSet set = new HashSet(listMap.get(key));
            listMap.get(key).clear();
            listMap.get(key).addAll(set);
        }
        return listMap;
    }

    /**
     * 找出所有字段
     *
     * @param object
     * @return
     */
    private static List<Field> getAllFields(Object object) {
        Class<?> aClass = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (aClass != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(aClass.getDeclaredFields())));
            aClass = aClass.getSuperclass();
            // log.info(aClass.getName());
        }
        return fieldList;
    }

    // 定义切点
    @Pointcut("execution(public * com.lznAdmin..*.*Controller.*(..))")
    public void fieldPointcut() {
    }

    @Around("fieldPointcut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        TimeInterval timer = DateUtil.timer();
        Object result = pjp.proceed();
        log.info("获取JSON数据 耗时:{}ms", timer.intervalRestart());
        this.parseDict(result);
        log.info("注入字典到JSON数据 耗时: {}ms", timer.interval());
        return result;
    }

    private void parseDict(Object result) {
        if (result instanceof lznAdminResult) {
            if (((lznAdminResult) result).getData() instanceof IPage) {
                List<JSONObject> resJsonList = new ArrayList<>();
                List<Map<String, String>> dictMapList = new ArrayList<>();
                List records = ((IPage) ((lznAdminResult) result).getData()).getRecords();
                if (records.size() <= 0) {
                    return;
                }
                for (Object entityData : records) {
                    List<Field> allFields = getAllFields(entityData);
                    JSONObject jsonData = JSONObject.parseObject(JSONObject.toJSONStringWithDateFormat(entityData, dateFormat));
                    for (Field field : allFields) {
                        Dict annotation = field.getAnnotation(Dict.class);
                        if (annotation != null) {
                            Map<String, String> dictMap = new HashMap<>();
                            dictMap.put(annotation.dicCode(), field.getName());
                            dictMapList.add(dictMap);
                            // log.info("annotation = {},{}", field.getName(), annotation.dicCode());
                        }
                    }
                    resJsonList.add(jsonData);
                }
                // 有Dict注解的
                if (dictMapList.size() > 0) {
                    Map<String, List<String>> dictListMap = listMapRemoveDuplicate(MapUtil.toListMap(dictMapList));
                    Map<String, List<DictVO>> translationDict = translationDict(dictListMap);
                    List<JSONObject> jsonObjects = replaceText(resJsonList, dictListMap, translationDict);
                    ((IPage) ((lznAdminResult) result).getData()).setRecords(jsonObjects);
                }
                // 无Dict注解的，解决无Dict注解的实体类@JSONField不生效问题
                ((IPage) ((lznAdminResult) result).getData()).setRecords(resJsonList);
            }
        }
    }


    // TODO: 2022/2/18 翻译表字段的方法

    // TODO: 2022/2/18 翻译普通字典的方法
    private Map<String, List<DictVO>> translationDict(Map<String, List<String>> dictListMap) {
        // log.info(dictListMap.toString());
        Map<String, List<DictVO>> dictList = new HashMap<>();
        for (String keyString : dictListMap.keySet()) {
            List<DictVO> DictVOListMap = commonAPI.translateDict(keyString);
            if (DictVOListMap == null) {
                continue;
            }
            dictList.put(keyString, DictVOListMap);
        }
        log.info("dictList = {}", dictList);
        return dictList;
    }

    /**
     * 根据字典将翻译出来的Text写入数据中
     *
     * @param results         JSON数据
     * @param dictListMap     需要翻译的字段及dictCode
     * @param translationDict 翻译好的字典
     * @return JSON数据
     */
    private List<JSONObject> replaceText(List<JSONObject> results, Map<String, List<String>> dictListMap, Map<String, List<DictVO>> translationDict) {
        for (JSONObject resItem : results) {
            for (String dictKey : dictListMap.keySet()) {
                List<String> fieldList = dictListMap.get(dictKey);
                if (fieldList == null) {
                    continue;
                }
                for (String field : fieldList) {
                    Object resItemValue = resItem.get(field);
                    if (resItemValue == null) {
                        continue;
                    }
                    String strResItemValue = resItemValue.toString();
                    List<DictVO> dictVOS = translationDict.get(dictKey);
                    if (dictVOS == null) {
                        continue;
                    }
                    // log.info(dictVOS.toString());
                    for (DictVO dictVO : dictVOS) {
                        // log.info(dictVO.toString());
                        if (String.valueOf(dictVO.getDictValue()).equals(strResItemValue)) {
                            resItem.put(field + "_text", dictVO.getDictText());
                        }
                    }
                }
            }
        }
        // log.info("finalResults={}",results);
        return results;
    }
}
